#include "Acceptor.h"
#include "TcpConnection.h"
#include "EventLoop.h"
#include <cerrno>
#include <sys/eventfd.h>

EventLoop::EventLoop(Acceptor &acceptor)
    : _epfd(createEpollFd()),
      _acceptor(acceptor),
      _isLooping(false),
      _evtArr(1000),
      _eventfd(createEventfd())
{
    addEpollReadEvent(_acceptor.fd());
    addEpollReadEvent(_eventfd);
}
EventLoop::~EventLoop()
{
    close(_epfd);
    close(_eventfd);
}
int EventLoop::createEventfd()
{
    int fd = eventfd(0, 0);
    if (fd < 0)
    {
        perror("eventfd");
    }
    return fd;
}
void EventLoop::handleReadEvent()
{
    uint64_t howmany = 0;
    int ret = read(_eventfd, &howmany, sizeof(howmany));
    printf("howmany %d\n", howmany);
    if (ret != sizeof(howmany))
    {
        perror("read");
    }
}
void EventLoop::wakeup()
{
    uint64_t one = 1;
    int ret = write(_eventfd, &one, sizeof(one));
    if (ret != sizeof(one))
    {
        perror("write");
    }
}
void EventLoop::runinLoop(Functor &&cb)
{
    {
        MutexLockGuard autolock(_mutex);
        _pendingFunctors.push_back(cb);
    }
    // 通知IO线程发送数据
    wakeup();
}
void EventLoop::doPendingFunctors()
{
    printf("do pendingFuntors\n");
    vector<Functor> tmp;
    {
        MutexLockGuard autolock(_mutex);
        tmp.swap(_pendingFunctors);
    }

    for (auto &t : tmp)
    {
        t();
    }
}
void EventLoop::loop()
{
    _isLooping = true;
    while (_isLooping)
    {
        waitEpollFd();
    }
}
void EventLoop::unloop()
{
    _isLooping = false;
}
void EventLoop::setAllCallbacks(Callback &&cb1, Callback &&cb2, Callback &&cb3)
{
    _onConnection = std::move(cb1);
    _onMessage = std::move(cb2);
    _onClose = std::move(cb3);
}
int EventLoop::createEpollFd()
{
    int epfd = epoll_create1(0);
    return epfd;
}
void EventLoop::addEpollReadEvent(int fd)
{
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.data.fd = fd;
    ev.events = EPOLLIN;
    int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);
    if (ret < 0)
    {
        perror("epoll_ctl");
    }
}
void EventLoop::delEpollReadEvent(int fd)
{
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.data.fd = fd;
    int ret = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, &ev);
    if (ret < 0)
    {
        perror("epoll_ctl");
    }
}
void EventLoop::waitEpollFd()
{
    int nready = epoll_wait(_epfd, _evtArr.data(), sizeof(_evtArr), 5000);
    if (nready == -1 && errno == EINTR)
    {
        return;
    }
    else if (nready == -1)
    {
        perror("epoll_wait");
    }
    else if (nready == 0)
    {
        printf("epoll time out\n");
    }
    else
    {
        for (int i = 0; i < nready; ++i)
        {
            // 找到已经就绪的描述符
            if (_evtArr[i].data.fd == _acceptor.fd())
            {
                handleNewConnection();
            }
            // 触发线程通知
            else if (_evtArr[i].data.fd == _eventfd)
            {
                handleReadEvent();
                doPendingFunctors();
            }
            else
            {
                handleMessage(_evtArr[i].data.fd);
            }
        }
    }
}
void EventLoop::handleNewConnection()
{
    // 有新连接到来
    int netfd = _acceptor.accept();
    // 添加监听
    addEpollReadEvent(netfd);
    // 创建TcpConnection对象
    TcpConnectionPtr conn(new TcpConnection(netfd,this));
    conn->setAllCallbacks(_onConnection,
                          _onMessage,
                          _onClose);
    _conns[netfd] = conn;
    conn->handleNewConnectionCallback();
}
void EventLoop::handleMessage(int fd)
{
    // 如果找到返回指向值的迭代器，未找到的就返回指向容器末尾的迭代器
    auto it = _conns.find(fd);
    if (it != _conns.end())
    {
        // 说明找到了
        bool isClose = it->second->isClosed();
        if (isClose)
        {
            it->second->handleCloseCallback();
            delEpollReadEvent(fd);
            _conns.erase(fd);
        }
        else
        {
            // 消息发送过来，触发处理Msg的回调函数
            it->second->handleMsgCallback();
        }
    }
}
